<script setup lang="ts">
import type { GenericEnvStore } from "@/modules/dev-env/store/generic-env-store.ts";
import { computed, nextTick, onMounted, shallowReactive, shallowRef, watch } from "vue";
import type { ToolInstallVersionItem } from "@/modules/dev-env/common/types.ts";
import type { BaseEnvMirror } from "@/modules/dev-env/mirror/mirror.ts";
import { showMessageAndPrint } from "@/framework/util/log.ts";
import { hc } from "@/framework/vue/util/render.ts";
import { CloudDownloadOutlined, CopyOutlined } from "@ant-design/icons-vue";
import type { UnzipCompleteArgs } from "@common/archives-file-types.ts";
import { noop } from "@/framework/util/warning.ts";
import { VirtList, type VirtListReturn } from "vue-virt-list";
import type { ItemSlotContext } from "@/framework/types/virt-list-types.ts";
import Grid from "@/components/framework/grid.vue";
import type { MirrorDataFilter } from "@/modules/dev-env/mirror/filter.ts";
import InstallMirrorFilter from "@/modules/dev-env/view/generic-env-install-mirror-filter.vue";
import type { MirrorQueryCondition } from "@/modules/dev-env/mirror/condition.ts";
import InstallMirrorCondition from "@/modules/dev-env/view/generic-env-install-mirror-condition.vue";
import { reduce } from "@/framework/util/arrays.ts";
import { setProp } from "@/framework/util/objects.ts";
import { useTaskStore } from "@/modules/dev-env/task/task-store.ts";
import { ArchiveInstallTask } from "@/modules/dev-env/task/archive-install-task.ts";
import { useSettingStore } from "@/store/setting-store.ts";
import { useDevEnvPanelStore } from "@/modules/dev-env/store/panel-store.ts";
import { copyText } from "@/util/clipboard.ts";
import { openExternal } from "@/util/shell.ts";

const { store, mirror } = defineProps<{
  store: GenericEnvStore<any>;
  mirror: BaseEnvMirror;
}>();

defineEmits<{
  (e: "cancel"): void;
}>();

const virtListRef = shallowRef<VirtListReturn<any>>();

const conditions = shallowRef<MirrorQueryCondition[]>([]);
const filters = shallowRef<MirrorDataFilter[]>([]);
const versionList = shallowRef<ToolInstallVersionItem[]>([]);
const renderList = computed(() => {
  if (filters.value.length === 0) {
    return versionList.value;
  }

  let list = versionList.value;
  for (let filter of filters.value) {
    list = filter.filter(list);
  }
  return list;
});
const loading = shallowRef(false);

watch(renderList, () => nextTick(() => virtListRef.value?.forceUpdate()));

const load = async () => {
  if (loading.value) return;
  loading.value = true;
  try {
    const query = reduce(conditions.value, (acc, it) => setProp(acc, it.field, it.value), {} as Record<string, any>);
    versionList.value = await mirror.getDownloadList(query);
  } catch (e) {
    showMessageAndPrint(e);
  } finally {
    loading.value = false;
  }
};

const onConditionReady = () => {
  if (conditions.value.filter(it => !it.ready).length === 0) {
    // 所有查询条件数据准备完毕
    load();
  }
};

// 查询条件变化时重新加载数据
const onConditionValueChange = () => {
  load();
};

onMounted(() => {
  conditions.value = mirror.getConditions().map(it => shallowReactive(it));
  filters.value = mirror.getFilters().map(it => shallowReactive(it));

  if (conditions.value.length === 0) {
    // 没有查询条件, 则直接加载数据
    load();
  }
});

const refresh = () => {
  load();
};

const settings = useSettingStore();
const taskStore = useTaskStore();
const panelStore = useDevEnvPanelStore();

const handleInstall = (version: ToolInstallVersionItem) => {
  panelStore.taskPanelOpen = true;
  const task = new ArchiveInstallTask(store, mirror, version, { deleteInstallerAfterInstall: settings.deletePackageAfterInstall });
  taskStore.addTask(task);
};

const onUnzipComplete = async (e: UnzipCompleteArgs, version: ToolInstallVersionItem) => {
  if (mirror.afterUnzipComplete) {
    await mirror.afterUnzipComplete(e, version);
  }
  if (store.afterUnzipComplete) {
    await store.afterUnzipComplete(e, version);
  }
  store.loadLocalVersions().catch(noop);
};
</script>

<template>
  <div class="position-relative h-500 overflow-y-auto">
    <grid rows-preset="two-rows-0" class="pb-10">
      <div class="ph-10">
        <a-form v-if="conditions.length > 0 || filters.length > 0" layout="inline" class="mb-16">
          <install-mirror-condition
            v-for="it in conditions"
            :key="it.field"
            :condition="it"
            @ready="onConditionReady"
            @change="onConditionValueChange"
          />
          <install-mirror-filter v-for="it in filters" :key="it.name" :filter="it" />
        </a-form>
      </div>

      <div class="border-top position-relative">
        <virt-list ref="virtListRef" :list="renderList" item-key="id" :min-size="35" item-class="tool-install-version-item">
          <template v-slot="{ itemData: it }: ItemSlotContext<ToolInstallVersionItem>">
            <div class="flex-1 flex aic col-gap-10">
              <span class="hover-underline curp" :title="it.url" @click.prevent="openExternal(it.url)">{{ it.name }}</span>
            </div>

            <a-space>
              <span class="color-text-secondary">{{ it.date }}</span>
              <a-button :icon="hc(CloudDownloadOutlined)" size="small" type="text" @click="handleInstall(it)">安装</a-button>
              <a-button :icon="hc(CopyOutlined)" size="small" type="text" title="复制下载地址" @click="copyText(it.url)"> 链接</a-button>
            </a-space>
          </template>
        </virt-list>

        <div v-if="loading" class="abs-fill flex-center">
          <a-spin spinning />
        </div>
      </div>
    </grid>
  </div>

  <div class="flex-sb ph-10">
    <span v-if="mirror.website" class="color-text-secondary curp hover-underline" @click="openExternal(mirror.website)">{{ mirror.website }}</span>
    <a-space>
      <a-button :loading="loading" @click="refresh">刷新</a-button>
      <a-button @click="$emit('cancel')">取消</a-button>
    </a-space>
  </div>
</template>

<style lang="less"></style>
